package org.sanguine.plugin.timetracker;

import java.awt.*;
import java.awt.event.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.swing.*;

import org.sanguine.plugin.timetracker.events.*;
import org.sanguine.plugin.timetracker.pojo.Project;
import org.sanguine.plugin.timetracker.pojo.Task;

import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.ui.popup.ActiveIcon;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;

/**
 * Created with IntelliJ IDEA. User: alex Date: 14.02.14 Time: 16:42 SVN $Id$
 */
public class MainDialogPanel implements ActionListener {
    private final TimerComponent timerComponent;
    private JPanel mainPanel;
    private JButton myTimesheetsButton;
    private JComboBox<Project> comboProject;
    private JComboBox<Task> comboTask;
    private JTextArea notes;
    private JLabel timerLabel;
    private JButton startStopButton;
    private JButton cancelButton;
    private volatile boolean startMode;
    private JBPopup mainDialog;
    private Integer selectedProjectId;
    private Integer selectedTaskId;

    MainDialogPanel(TimerComponent component) {
        timerComponent = component;
        createUIComponents();
    }

    private void createUIComponents() {
        ActionListener startStopListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                onStartStop();
            }
        };

        startStopButton.addActionListener(startStopListener);
        mainPanel.registerKeyboardAction(startStopListener, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        ActionListener cancelListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                closeDialog();
            }
        };

        cancelButton.addActionListener(cancelListener);
        mainPanel.registerKeyboardAction(cancelListener, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        setStartMode();

        comboProject.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    Project selected = (Project) e.getItem();
                    selectedProjectId = selected.id;
                    updateTaskCombobox(selected.tasks);
                }
            }
        });

        comboTask.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    Task selected = (Task) e.getItem();
                    selectedTaskId = selected.id;
                }
            }
        });
    }

    private void updateTime(final double time) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                int hours = (int) time;
                long minutes = Math.round((time - Math.rint(time)) * 60);
                timerLabel.setText(String.format("%2d:%02d", hours, minutes));
            }
        });
    }

    private void setStartMode() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                startStopButton.setText("Start");
            }
        });
        notes.requestFocusInWindow();
        startMode = true;
    }

    private void setStopMode() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                startStopButton.setText("Stop");
            }
        });
        startStopButton.requestFocusInWindow();
        startMode = false;
    }

    private void closeDialog() {
        if (mainDialog != null && mainDialog.isVisible()) {
            mainDialog.dispose();
        }
    }

    private void openDialog(final DataContext context, com.intellij.openapi.project.Project project, Icon icon) {
        mainDialog = JBPopupFactory.getInstance()
                .createComponentPopupBuilder($$$getRootComponent$$$(), startStopButton)
                .setShowShadow(true)
                .setProject(project)
                .setTitleIcon(new ActiveIcon(icon))
                .setMovable(true)
                .setTitle("Tracker Timer")
                .setRequestFocus(true)
                .createPopup();
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                mainDialog.showInBestPositionFor(context);
            }
        });
    }

    private void onStartStop() {
        if (startMode) {
            startTimer();
        } else {
            stopTimer();
        }
        closeDialog();
    }

    private void startTimer() {
        StartTimerEvent event = new StartTimerEvent(this, 0, "", (Project) comboProject.getSelectedItem(), (Task) comboTask.getSelectedItem(), notes.getText());
        timerComponent.processEvent(event);
    }

    private void stopTimer() {
        StopTimerEvent event = new StopTimerEvent(this, 0, "");
        timerComponent.processEvent(event);
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        if (e instanceof OpenTimerDialogEvent) {
            openDialog(((OpenTimerDialogEvent) e).getContext(), ((OpenTimerDialogEvent) e).getProject(),
                    ((OpenTimerDialogEvent) e).getIcon());
        } else if (e instanceof TimerStartedEvent) {
            updateTime(((TimerStartedEvent) e).getTimerValue());
            setStopMode();
        } else if (e instanceof TimerStoppedEvent) {
            updateTime(((TimerStoppedEvent) e).getTimerValue());
            setStartMode();
        } else if (e instanceof TimerValueUpdatedEvent) {
            updateTime(((TimerValueUpdatedEvent) e).getTimerValue());
        } else if (e instanceof UpdateProjectsEvent) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    updateComboboxes(((UpdateProjectsEvent) e).getProjects());
                }
            });
        }
    }

    private void updateActiveTimerInfo(Project activeProject, Task activeTask, String activeNotes) {
        if (activeProject != null && activeTask != null) {
            Integer posOfProject = getIndexOfProject(activeProject);
            Integer posOfTask = getIndexOfTask(activeTask);
            if (posOfProject != null && posOfTask != null) {
                comboProject.setSelectedIndex(posOfProject);
                comboTask.setSelectedIndex(posOfTask);
                selectedProjectId = activeProject.id;
                selectedTaskId = activeTask.id;
                if (notes != null) {
                    notes.setText(activeNotes);
                } else {
                    notes.setText("");
                }
            }
        }
    }

    private Integer getIndexOfTask(Task task) {
        Integer posOfTask = null;
        for (int i = 0; i < comboTask.getItemCount(); i++) {
            if (task.id.equals(comboTask.getItemAt(i))) {
                posOfTask = i;
                break;
            }
        }
        return posOfTask;
    }

    private Integer getIndexOfProject(Project project) {
        Integer posOfProject = null;
        for (int i = 0; i < comboProject.getItemCount(); i++) {
            if (project.id.equals(comboProject.getItemAt(i))) {
                posOfProject = i;
                break;
            }
        }
        return posOfProject;
    }

    private void updateComboboxes(java.util.List<Project> projects) {
        if (projects == null || projects.isEmpty())
            return;

        Collections.sort(projects, new Comparator<Project>() {
            @Override
            public int compare(Project o1, Project o2) {
                if (o1.name == null) {
                    return 1;
                }
                return o1.name.compareToIgnoreCase(o2.name);
            }
        });


        comboProject.removeAllItems();
        int i = 0;
        int index = 0;
        List<Task> tasks = Collections.emptyList();
        for (Project project : projects) {
            if (project.id.equals(selectedProjectId)) {
                index = i;
                tasks = project.tasks;
            }
            comboProject.insertItemAt(project, i++);
        }
        comboProject.setSelectedIndex(index);

        if (index == 0) {
            selectedProjectId = comboProject.getItemAt(0).id;
        }

        updateTaskCombobox(tasks);
    }

    private void updateTaskCombobox(List<Task> tasks) {
        if (tasks == null || tasks.isEmpty())
            return;

        Collections.sort(tasks, new Comparator<Task>() {
            @Override
            public int compare(Task o1, Task o2) {
                if (o1.name == null) {
                    return 1;
                }
                return o1.name.compareToIgnoreCase(o2.name);
            }
        });

        comboTask.removeAllItems();
        int i = 0;
        int index = 0;
        for (Task task : tasks) {
            if (task.id.equals(selectedTaskId)) {
                index = i;
            }
            comboTask.insertItemAt(task, i++);
        }
        comboTask.setSelectedIndex(index);

        if (index == 0) {
            selectedTaskId = comboTask.getItemAt(0).id;
        }
    }

    {
        // GUI initializer generated by IntelliJ IDEA GUI Designer
        // >>> IMPORTANT!! <<<
        // DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer >>> IMPORTANT!! <<< DO NOT edit this method OR call it in your
     * code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        mainPanel = new JPanel();
        mainPanel.setLayout(new GridLayoutManager(5, 4, new Insets(5, 5, 5, 5), -1, -1));
        mainPanel.setMinimumSize(new Dimension(310, 213));
        mainPanel.setOpaque(true);
        mainPanel.setPreferredSize(new Dimension(310, 213));
        final JLabel label1 = new JLabel();
        label1.setText("Project / Task");
        mainPanel.add(label1, new GridConstraints(0, 0, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        comboProject = new JComboBox();
        comboProject.setToolTipText("Project");
        mainPanel.add(comboProject, new GridConstraints(1, 0, 1, 4, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED,
                new Dimension(300, -1), new Dimension(300, -1), new Dimension(300, -1), 0, false));
        comboTask = new JComboBox();
        comboTask.setToolTipText("Task");
        mainPanel.add(comboTask, new GridConstraints(2, 0, 1, 4, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED,
                new Dimension(300, -1), new Dimension(300, -1), new Dimension(300, -1), 0, false));
        startStopButton = new JButton();
        startStopButton.setSelected(true);
        startStopButton.setText("Start");
        mainPanel.add(startStopButton, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        mainPanel.add(panel1,
                new GridConstraints(3, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null,
                        0, false));
        panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "Notes"));
        final JScrollPane scrollPane1 = new JScrollPane();
        panel1.add(scrollPane1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_BOTH,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0,
                false));
        notes = new JTextArea();
        notes.setLineWrap(true);
        notes.setMargin(new Insets(5, 5, 5, 5));
        notes.setToolTipText("Notes (optional)");
        scrollPane1.setViewportView(notes);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        mainPanel.add(panel2,
                new GridConstraints(3, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null,
                        0, false));
        panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "Time"));
        timerLabel = new JLabel();
        timerLabel.setFont(new Font(timerLabel.getFont().getName(), timerLabel.getFont().getStyle(), 36));
        timerLabel.setHorizontalAlignment(0);
        timerLabel.setHorizontalTextPosition(0);
        timerLabel.setText("0:00");
        timerLabel.setToolTipText("Time spent");
        timerLabel.setVerticalAlignment(0);
        timerLabel.setVerticalTextPosition(1);
        panel2.add(timerLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(84, 44), null,
                0, false));
        myTimesheetsButton = new JButton();
        myTimesheetsButton.setBackground(new Color(-1447447));
        myTimesheetsButton.setEnabled(true);
        myTimesheetsButton.setFont(new Font(myTimesheetsButton.getFont().getName(), myTimesheetsButton.getFont()
                .getStyle(), myTimesheetsButton.getFont().getSize()));
        myTimesheetsButton.setForeground(new Color(-43761));
        myTimesheetsButton.setHideActionText(false);
        myTimesheetsButton.setSelected(false);
        myTimesheetsButton.setText("My timesheets");
        myTimesheetsButton.setToolTipText("Open HARVEST Timesheet in Browser");
        myTimesheetsButton.setVerifyInputWhenFocusTarget(true);
        myTimesheetsButton.setVerticalAlignment(0);
        mainPanel.add(myTimesheetsButton, new GridConstraints(4, 3, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK
                | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                false));
        cancelButton = new JButton();
        cancelButton.setText("Cancel");
        mainPanel.add(cancelButton, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
                null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        mainPanel.add(spacer1, new GridConstraints(4, 2, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK
                | GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return mainPanel;
    }
}
